/****************************************************************************
**
** AnimationManager.cpp
**
** Copyright (C) August 2014 Hotride
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
*****************************************************************************
*/
//---------------------------------------------------------------------------
#include "stdafx.h"
//----------------------------------------------------------------------------
TAnimationManager::TAnimationManager()
: m_AddressAnimData(0), m_Width(0), m_Height(0)
{
	m_Data = NULL;
	memset(m_AddressIdx, 0, sizeof(m_AddressIdx));
	memset(m_AddressMul, 0, sizeof(m_AddressMul));
	memset(m_SizeIdx, 0, sizeof(m_SizeIdx));
	memset(m_DataIndex, 0, sizeof(m_DataIndex));
}
//----------------------------------------------------------------------------
void TAnimationManager::Load(PDWORD verdata)
{
	IFOR(i, 0, 0x800)
	{
		WORD AnimID = 0;
		int FindID = 0;

		if (i >= 200)
		{
			if (i >= 400) //People
			{
				AnimID = i - 400;
				FindID = ((AnimID * 175) + 35000) * sizeof(ANIM_IDX_BLOCK);
			}
			else //Low
			{
				AnimID = i - 200;
				FindID = ((AnimID * 65) + 22000) * sizeof(ANIM_IDX_BLOCK);
			}
		}
		else //Hight
		{
			AnimID = i;
			FindID = (AnimID * 110) * sizeof(ANIM_IDX_BLOCK);
		}
			
		if (FindID >= m_SizeIdx[0]) continue;

		PANIM_IDX_BLOCK aidx = (PANIM_IDX_BLOCK)(m_AddressIdx[0] + FindID);
			
		if (aidx->Size && aidx->Position != 0xFFFFFFFF && aidx->Size != 0xFFFFFFFF)
		{
			m_DataIndex[i].Address = (DWORD)aidx;
			m_DataIndex[i].Offset = m_AddressMul[0];
			m_DataIndex[i].ID = AnimID;
		}
	}

	if (verdata != NULL)
	{
		int DataCount = *verdata;

		if (DataCount)
		{
			IFOR(i, 0, DataCount)
			{
				PVERDATA_HEADER vh = (PVERDATA_HEADER)((DWORD)verdata + 4 + (i * sizeof(VERDATA_HEADER)));

				if (vh->FileID == 0x06) //Anim
				{
					//trace_printf("vh->ID = 0x%02X vh->BlockID = 0x%04X\n", vh->FileID, vh->BlockID);
					/*WORD i = vh->BlockID;
					if (i >= 0x00C8)
					{
						if (i >= 0x0190) //People
						{
							WORD AnimID = i - 0x0190;
							WORD FindID = (AnimID * 0xAF) + 0x88B8;
							PANIM_IDX_BLOCK aidx = (PANIM_IDX_BLOCK)(verdata + vh->Position + (FindID * sizeof(ANIM_IDX_BLOCK)));

							if (aidx->Size && aidx->Position != 0xFFFFFFFF && aidx->Size != 0xFFFFFFFF)
							{
								//m_DataIndex[i].IndexFile = (DWORD)m_AddressIdx[0];
								//m_DataIndex[i].DataFile = (DWORD)m_AddressMul[0];
								m_DataIndex[i].Address = (DWORD)m_AddressMul[0] + aidx->Position;
								m_DataIndex[i].ID = AnimID;
							}
						}
						else //Low
						{
							WORD AnimID = i - 0x00C8;
							WORD FindID = (AnimID * 0x41) + 0x55F0;
							PANIM_IDX_BLOCK aidx = (PANIM_IDX_BLOCK)(verdata + vh->Position + (FindID * sizeof(ANIM_IDX_BLOCK)));

							if (aidx->Size && aidx->Position != 0xFFFFFFFF && aidx->Size != 0xFFFFFFFF)
							{
								//m_DataIndex[i].IndexFile = (DWORD)m_AddressIdx[0];
								//m_DataIndex[i].DataFile = (DWORD)m_AddressMul[0];
								m_DataIndex[i].Address = (DWORD)m_AddressMul[0] + aidx->Position;
								m_DataIndex[i].ID = AnimID;
							}
						}
					}
					else //Hight
					{
						WORD FindID = i * 0x6E;
						PANIM_IDX_BLOCK aidx = (PANIM_IDX_BLOCK)(verdata + vh->Position + (FindID * sizeof(ANIM_IDX_BLOCK)));

						if (aidx->Size && aidx->Position != 0xFFFFFFFF && aidx->Size != 0xFFFFFFFF)
						{
							//m_DataIndex[i].IndexFile = (DWORD)m_AddressIdx[0];
							//m_DataIndex[i].DataFile = (DWORD)m_AddressMul[0];
							m_DataIndex[i].Address = (DWORD)m_AddressMul[0] + aidx->Position;
							m_DataIndex[i].ID = i;
						}
					}*/
				}
			}
		}
	}
}
//----------------------------------------------------------------------------
void TAnimationManager::InitBodyconv(PDWORD verdata, string fName)
{
	Load(verdata);

	FILE *file = fopen(fName.c_str(), "r");

	if (file != NULL)
	{
		while (!feof(file))
		{
			char text[1024] = {0};
			fgets(text, 1024, file);

			if (!strlen(text) || !isalnum(text[0])) continue;

			int tCount = 0;
			char *ptr = text;
			char *end = text + strlen(text);

			while (ptr < end)
			{
				if (*ptr == '\t') tCount++;
				ptr++;
			}
		
			int index = 0;
			sscanf(text, "%i", &index);

			if (index >= 0 && index < 0x0800)
			{
				int idx = 0;
				int Anim2 = -1;
				int Anim3 = -1;
				int Anim4 = -1;
				int Anim5 = -1;

				if (tCount == 1) //Anim2
				{
					sscanf(text, "%i\t%i", &idx, &Anim2);
				}
				else if (tCount == 2) //Anim2, Anim3
				{
					sscanf(text, "%i\t%i\t%i", &idx, &Anim2, &Anim3);
				}
				else if (tCount == 3) //Anim2, Anim3, Anim4
				{
					sscanf(text, "%i\t%i\t%i\t%i", &idx, &Anim2, &Anim3, &Anim4);
				}
				else if (tCount >= 4) //Anim2, Anim3, Anim4, Anim5
				{
					sscanf(text, "%i\t%i\t%i\t%i\t%i", &idx, &Anim2, &Anim3, &Anim4, &Anim5);
				}
				
				//trace_printf("\tIndex=%i tCount=%i 2=%i 3=%i 4=%i 5=%i\n", idx, tCount, Anim2, Anim3, Anim4, Anim5);

				int StartAnimID = -1;
				int AnimFile = 1;
				WORD ConvertedAnimID = 0;
				
				if (Anim2 != -1 && m_AddressIdx[2] != NULL && m_AddressMul[2] != NULL)
				{
					AnimFile = 2;

					if (Anim2 >= 200) //Low
					{
						ConvertedAnimID = Anim2 - 200;
						StartAnimID = (ConvertedAnimID * 65) + 22000;
					}
					else //Hight
					{
						StartAnimID = Anim2 * 110;
						ConvertedAnimID = Anim2;
					}
				}
				else if (Anim3 != -1 && m_AddressIdx[3] != NULL && m_AddressMul[3] != NULL)
				{
					AnimFile = 3;

					if (Anim3 >= 200)
					{
						if (Anim3 >= 400) //People
						{
							ConvertedAnimID = Anim3 - 400;
							StartAnimID = (ConvertedAnimID * 175) + 35000;
						}
						else //Low
						{
							ConvertedAnimID = Anim3 - 200;
							StartAnimID = (ConvertedAnimID * 110) + 22000;
						}
					}
					else //Hight
					{
						ConvertedAnimID = Anim3;
						StartAnimID = (Anim3 * 65) + 9000;
					}
				}
				else if (Anim4 != -1 && m_AddressIdx[4] != NULL && m_AddressMul[4] != NULL)
				{
					AnimFile = 4;

					if (Anim4 >= 200)
					{
						if (Anim4 >= 400) //People
						{
							ConvertedAnimID = Anim4 - 400;
							StartAnimID = (ConvertedAnimID * 175) + 35000;
						}
						else //Low
						{
							ConvertedAnimID = Anim4 - 200;
							StartAnimID = (ConvertedAnimID * 65) + 22000;
						}
					}
					else //Hight
					{
						ConvertedAnimID = Anim4;
						StartAnimID = Anim4 * 110;
					}
				}
				else if (Anim5 != -1 && m_AddressIdx[5] != NULL && m_AddressMul[5] != NULL)
				{
					AnimFile = 5;

					if (Anim5 >= 200)
					{
						if (Anim5 >= 400) //People
						{
							ConvertedAnimID = Anim5 - 400;
							StartAnimID = (ConvertedAnimID * 175) + 35000;
						}
						else //Low
						{
							ConvertedAnimID = Anim5 - 200;
							StartAnimID = (ConvertedAnimID * 65) + 22000;
						}
					}
					else //Hight
					{
						ConvertedAnimID = Anim5;
						StartAnimID = Anim5 * 110;
					}
				}

				if (AnimFile != 1 && StartAnimID != -1)
				{
					StartAnimID = StartAnimID * sizeof(ANIM_IDX_BLOCK);

					if (StartAnimID < m_SizeIdx[AnimFile])
					{
						PANIM_IDX_BLOCK aidx = (PANIM_IDX_BLOCK)(m_AddressIdx[AnimFile] + (StartAnimID));

						if (aidx->Size && aidx->Position != 0xFFFFFFFF && aidx->Size != 0xFFFFFFFF)
						{
							m_DataIndex[idx].Address = (DWORD)aidx;
							m_DataIndex[idx].Offset = m_AddressMul[AnimFile];
							m_DataIndex[idx].ID = ConvertedAnimID;
						}
					}
				}
			}
		}

		fclose(file);
	}
	else
	{
		TPRINT("Bodyconv.def is not found!\n");
	}
}
//----------------------------------------------------------------------------
void TAnimationManager::ExecuteAnim(ANIM_FRAME &af, WORD ID, WORD Color, bool PartialHue, int &Offset, BYTE &Frame)
{
	af.Reset();

	if (ID > 0x0800 || m_DataIndex[ID].Address == NULL) return;

	PANIM_IDX_BLOCK aidx = (PANIM_IDX_BLOCK)(m_DataIndex[ID].Address + Offset);
	
	if (aidx->Size && aidx->Position != 0xFFFFFFFF && aidx->Size != 0xFFFFFFFF)
	{
		if (m_Color)
		{
			Color = m_Color;
			PartialHue = false;
		}

		PWORD DataStart = (PWORD)(m_DataIndex[ID].Offset + aidx->Position);

		PWORD ptr = DataStart;

		DataStart = (PWORD)((DWORD)DataStart + sizeof(WORD[256])); //Palette

		PWORD Palette = ptr;
		ptr = (PWORD)((DWORD)ptr + sizeof(WORD[256])); //Palette

		int FrameCount = *((PDWORD)ptr);
		ptr = (PWORD)((DWORD)ptr + sizeof(DWORD));

		if (Frame >= FrameCount)
		{
			if (!FrameCount) return;
			Frame = 0;
		}

		PDWORD FrameOffset = (PDWORD)ptr;
		ptr = (PWORD)((DWORD)ptr + (FrameCount * sizeof(DWORD)));

		PWORD P = (PWORD)((DWORD)DataStart + FrameOffset[Frame]);

		short ImageCenterX = *P;
		af.ImageCenterX = ImageCenterX;
		P++;

		short ImageCenterY = *P;
		af.ImageCenterY = ImageCenterY;
		P++;

		WORD ImageWidth = *P;
		af.Width = ImageWidth;
		P++;

		WORD ImageHeight = *P;
		af.Height = ImageHeight;
		P++;

		int X = 0;
		int Y = 0;

		int blocksize = ImageWidth * ImageHeight * 4;
		PDWORD pData = (PDWORD)malloc(blocksize);
		memset(pData, 0, blocksize);

		WORD PrevLineNum = 0xFF;

		while (true)
		{
			WORD RowHeader = *P;
			P++;

			WORD RowOfs = *P;
			P++;

			if (RowHeader == 0x7FFF || RowOfs == 0x7FFF) break;

			WORD RunLength = RowHeader & 0xFFF;
			WORD LineNum = RowHeader >> 12;

			X = (RowOfs >> 6) & 0x3FF;

			if (RowOfs & 0x8000) X = ImageCenterX + X - 0x400;
			else X = ImageCenterX + X;

			if (PrevLineNum != 0xFF && LineNum != PrevLineNum) Y++;
			PrevLineNum = LineNum;

			if (Y >= 0)
			{
				if (Y >= ImageHeight) break;

				PBYTE B = (PBYTE)P;
				IFOR(j, 0, RunLength)
				{
					DWORD pcl = (PartialHue ? UO->m_ColorManager->GetPartialHueColor(Palette[*B], Color) : UO->m_ColorManager->GetColor(Palette[*B], Color));
					if (Palette[*B])
					{
						int Block = Y * ImageWidth + (X + j);
						if (g_GrayedPixels) pData[Block] = (0xFF << 24) | (GetRValue(pcl) << 16) | (GetRValue(pcl) << 8) | GetRValue(pcl);
						else pData[Block] = (0xFF << 24) | (GetBValue(pcl) << 16) | (GetGValue(pcl) << 8) | GetRValue(pcl);
					}

					B++;
				}

				P = (PWORD)((DWORD)P + RunLength);
			}
		}

		Frame++;

		UO->m_GL.BindTexture(af.Texture, ImageWidth, ImageHeight, pData);

		free(pData);
	}
}
//----------------------------------------------------------------------------
bool TAnimationManager::TextAnimPixels(ANIM_FRAME_INFO &af, int &CheckX, int &CheckY)
{
	PWORD Palette = af.Palette;
	PWORD P = af.Address;

	short ImageCenterX = af.ImageCenterX;
	short ImageCenterY = af.ImageCenterY;
	WORD ImageWidth = af.Width;
	WORD ImageHeight = af.Height;

	int X = 0;
	int Y = 0;

	WORD PrevLineNum = 0xFF;

	while (true)
	{
		WORD RowHeader = *P;
		P++;

		WORD RowOfs = *P;
		P++;

		if (RowHeader == 0x7FFF || RowOfs == 0x7FFF) break;

		WORD RunLength = RowHeader & 0xFFF;
		WORD LineNum = RowHeader >> 12;

		X = (RowOfs >> 6) & 0x3FF;

		if (RowOfs & 0x8000) X = ImageCenterX + X - 0x400;
		else X = ImageCenterX + X;

		if (PrevLineNum != 0xFF && LineNum != PrevLineNum) Y++;
		PrevLineNum = LineNum;

		if (Y >= 0)
		{
			if (Y >= ImageHeight) break;

			PBYTE B = (PBYTE)P;

			IFOR(j, 0, RunLength)
			{
				if ((X + j) == CheckX && Y == CheckY) return (Palette[*B] != 0);

				B++;
			}

			P = (PWORD)((DWORD)P + RunLength);
		}
	}

	return false;
}
//----------------------------------------------------------------------------
void TAnimationManager::GetAnimInformation(ANIM_FRAME_INFO &af, WORD ID, int Offset, BYTE &Frame)
{
	af.Reset();

	if (ID > 0x0800 || m_DataIndex[ID].Address == NULL) return;
	
	PANIM_IDX_BLOCK aidx = (PANIM_IDX_BLOCK)(m_DataIndex[ID].Address + Offset);
	
	if (aidx->Size && aidx->Position != 0xFFFFFFFF && aidx->Size != 0xFFFFFFFF)
	{
		PWORD DataStart = (PWORD)(m_DataIndex[ID].Offset + aidx->Position);
		PBYTE ptr = (PBYTE)DataStart;

		af.Palette = (PWORD)ptr;

		DataStart = (PWORD)((DWORD)DataStart + sizeof(WORD[256])); //Palette
		ptr += sizeof(WORD[256]);

		int FrameCount = *((PDWORD)ptr);
		ptr += sizeof(DWORD);

		if (Frame >= FrameCount)
		{
			if (!FrameCount) return;
			Frame = 0;
		}

		PDWORD FrameOffset = (PDWORD)ptr;
		ptr += (FrameCount * sizeof(DWORD));

		DataStart = (PWORD)((DWORD)DataStart + FrameOffset[Frame]);

		af.ImageCenterX = (short)*DataStart++;
		af.ImageCenterY = (short)*DataStart++;
		af.Width = (WORD)*DataStart++;
		af.Height = (WORD)*DataStart++;
		af.FrameCount = (BYTE)FrameCount;
		af.Address = (PWORD)DataStart;
	}
}
//----------------------------------------------------------------------------
void TAnimationManager::DrawCharacter(TGameObject *obj, float X, float Y, float Z)
{
	const int LayerCount = 19;

	int UsedLayers[LayerCount] =
	{
		LAYER_SHIRT,	//
		LAYER_ARMS,		//"Arms"
		LAYER_PANTS,	//
		LAYER_SHOES,	//
		LAYER_LEGS,		//"Legs"
		LAYER_TORSO,	//"Torso"
		LAYER_BRACELET, //
		LAYER_GLOVES,	//"Gloves"
		LAYER_TUNIC, //
		LAYER_SKIRT, //
		LAYER_NECK,		//"Neck"
		LAYER_HAIR,		//"Hair"
		LAYER_ROBE,		//"Robe"
		LAYER_FACIAL_HAIR, //"Beard"
		LAYER_HELM,		//"Helmet"
		LAYER_WAIST, //
		LAYER_ONE_HANDED, //"Rhand"
		LAYER_CLOAK,	//"Cloak"
		LAYER_TWO_HANDED //"Lhand"
	};

	BYTE Dir = 0;
	POINT3DF Position = {0.0f, 0.0f, 0};

	obj->GetAnimationInfo(Position, Dir, true);

	bool Mirror = false;

	switch (Dir)
	{
		case 2:
		case 4:
		{
			if (Dir == 2) Mirror = true;
			Dir = 1;
			break;
		}
		case 1:
		case 5:
		{
			if (Dir == 1) Mirror = true;
			Dir = 2;
			break;
		}
		case 0:
		case 6:
		{
			if (Dir == 0) Mirror = true;
			Dir = 3;
			break;
		}
		case 3:
		{
			Dir = 0;
			break;
		}
		case 7:
		{
			Dir = 4;
			break;
		}
		default: break;
	}

	WORD TargetColor = 0;
	bool NeedHPLine = false;

	if ((obj->GetSerial() == g_LastAttackObject || obj->GetSerial() == g_LastTargetObject) && obj->GetSerial() != UO->GetPlayerSerial())
	{
		switch ((NOTORIETY_TYPE)obj->GetNotoriety())
		{
			case NT_INNOCENT:
			{
				TargetColor = UO->m_ConfigManager.GetInnocentColor();
				NeedHPLine = true;
				break;
			}
			case NT_FRIENDLY:
			{
				TargetColor = UO->m_ConfigManager.GetFriendlyColor();
				NeedHPLine = true;
				break;
			}
			case NT_SOMEONE_GRAY:
			{
				TargetColor = UO->m_ConfigManager.GetSomeoneColor();
				NeedHPLine = true;
				break;
			}
			case NT_CRIMINAL:
			{
				TargetColor = UO->m_ConfigManager.GetCriminalColor();
				NeedHPLine = true;
				break;
			}
			case NT_ENEMY:
			{
				TargetColor = UO->m_ConfigManager.GetEnemyColor();
				NeedHPLine = true;
				break;
			}
			case NT_MURDERER:
			{
				TargetColor = UO->m_ConfigManager.GetMurdererColor();
				NeedHPLine = true;
				break;
			}
			default: break;
		}
	}
	
	if (obj->Hidden()) m_Color = 0x038A;
	else if (obj->GetSerial() == g_LastAttackObject) m_Color = TargetColor;
	else m_Color = 0;

	BYTE AnimIndex = obj->GetAnimIndex();
	BYTE AnimGroup = obj->GetAnimationGroup();
	
	int Offset = (((AnimGroup * 5) + Dir) * 12);
	
	BYTE FrameIndex = AnimIndex;
	
	TGameObject *goi = obj->FindLayer(LAYER_MOUNT);
	
	int DrawX = X + Position.x;
	int DrawY = Y + Position.y;
	
	if (goi != NULL) //Draw mount
	{
		BYTE AnimGroupM = obj->GetAnimationGroup(goi->GetMountAnimation());
		int OffsetM = (((AnimGroupM * 5) + Dir) * 12);
		Draw(goi, DrawX + 3, DrawY, Z, Mirror, OffsetM, FrameIndex, goi->GetMountAnimation());
	}
	
	FrameIndex = AnimIndex;

	Draw(obj, DrawX, DrawY, Z, Mirror, Offset, AnimIndex); //Draw character

	if (obj->IsHuman())
	{
		if (!obj->Dead())
		{
			IFOR(l, 0, LayerCount)
			{
				goi = obj->FindLayer(UsedLayers[l]);
				if (goi != NULL && goi->GetAnimID())
				{
					BYTE Frame = FrameIndex;
					Draw(goi, DrawX, DrawY, Z, Mirror, Offset, Frame, goi->GetAnimID()); //Draw layred objects
				}
			}
		}
		else
		{
			goi = obj->FindLayer(LAYER_ROBE);
			if (goi != NULL && goi->GetAnimID())
			{
				BYTE Frame = FrameIndex;
				Draw(goi, DrawX, DrawY, Z, Mirror, Offset, Frame, goi->GetAnimID()); //Draw layred objects
			}
		}
	}

	if (NeedHPLine)
	{
		UO->DrawGump(0x1068, TargetColor, DrawX - 20, DrawY - (Z * 4));

		int Per = obj->GetMaxHits();
		if (Per > 0)
		{
			Per = (obj->GetHits() * 100) / Per;
			if (Per > 100) Per = 100;

			if (Per > 1)
			{
				Per = (34 * Per) / 100;

				UO->DrawGump(0x1069, TargetColor, DrawX - 20, DrawY - (Z * 4), Per, 0);
			}
		}
	}
}
//----------------------------------------------------------------------------
void TAnimationManager::Draw(TGameObject *obj, float X, float Y, float Z, bool &Mirror, int &Offset, BYTE &AnimIndex, WORD ID)
{
	if (obj == NULL) return;

	bool PartialHue = obj->IsPartialHue();

	if (!ID)
	{
		PartialHue = obj->IsHuman();
		ID = obj->GetMountAnimation();
	}
	
	ANIM_FRAME af = {0};
	ExecuteAnim(af, ID, obj->GetColor(), PartialHue, Offset, AnimIndex);

	if (af.Width)
	{
		int OffsCX = 0;
		int OffsCY = 0;
		
		if (Mirror) OffsCX = -(af.Width - af.ImageCenterX);
		else OffsCX = -af.ImageCenterX;
		OffsCY = -(af.Height + af.ImageCenterY + 3);

		UO->m_GL.Draw(af.Texture, X + OffsCX, (Y + OffsCY) - (Z * 4), af.Width, af.Height, Mirror);
		glDeleteTextures(1, &af.Texture);
	}

	DWORD ticks = GetTickCount();

	if (obj->GetLastFrameTime() < ticks)
	{
		obj->SetAnimIndex(AnimIndex);
		obj->SetLastFrameTime(ticks + (UO->m_ConfigManager.GetStandartCharactersAnimationDelay() ? 0x50 : 50));
	}
}
//----------------------------------------------------------------------------
bool TAnimationManager::CharacterPixelsInXY(TGameObject *obj, int X, int Y, int Z)
{
	const int UsedLayers[12] =
	{
		11, //"Hair"
		16, //"Beard"
		7, //"Gloves"
		24, //"Legs"
		13, //"Torso"
		10, //"Neck"
		19, //"Arms"
		22, //"Robe"
		20, //"Cloak"
		6, //"Helmet"
		1, //"Rhand"
		2 //"Lhand"
	};

	BYTE Dir = 0;
	POINT3DF Position = {0.0f, 0.0f, 0};

	obj->GetAnimationInfo(Position, Dir);

	bool Mirror = false;

	switch (Dir)
	{
		case 2:
		case 4:
		{
			if (Dir == 2) Mirror = true;
			Dir = 1;
			break;
		}
		case 1:
		case 5:
		{
			if (Dir == 1) Mirror = true;
			Dir = 2;
			break;
		}
		case 0:
		case 6:
		{
			if (Dir == 0) Mirror = true;
			Dir = 3;
			break;
		}
		case 3:
		{
			Dir = 0;
			break;
		}
		case 7:
		{
			Dir = 4;
			break;
		}
		default: break;
	}

	BYTE AnimIndex = obj->GetAnimIndex();
	BYTE AnimGroup = obj->GetAnimationGroup();
	
	int Offset = (((AnimGroup * 5) + Dir) * 12);
	
	BYTE FrameIndex = AnimIndex;
	
	TGameObject *goi = obj->FindLayer(LAYER_MOUNT);
	
	int DrawX = X - Position.x;
	int DrawY = Y - Position.y;
	
	if (goi != NULL) //Check mount
	{
		BYTE AnimGroupM = obj->GetAnimationGroup(goi->GetMountAnimation());
		int OffsetM = (((AnimGroupM * 5) + Dir) * 12);

		if (TestPixels(goi, DrawX - 3, DrawY, Z, Mirror, OffsetM, FrameIndex, goi->GetMountAnimation())) return true;
	}
	
	FrameIndex = AnimIndex;

	if (TestPixels(obj, DrawX, DrawY, Z, Mirror, Offset, AnimIndex)) return true; //Check character

	if (obj->IsHuman())
	{
		for (int l = 0; l < 12; l++)
		{
			goi = obj->FindLayer(UsedLayers[l]);
			if (goi != NULL && goi->GetAnimID())
			{
				BYTE Frame = FrameIndex;
				if (TestPixels(goi, DrawX, DrawY, Z, Mirror, Offset, Frame, goi->GetAnimID())) return true; //Check layred objects
			}
		}
	}

	return false;
}
//----------------------------------------------------------------------------
bool TAnimationManager::TestPixels(TGameObject *obj, int X, int Y, int Z, bool &Mirror, int &Offset, BYTE &AnimIndex, WORD ID)
{
	if (obj == NULL) return false;

	if (!ID) ID = obj->GetMountAnimation();
	
	ANIM_FRAME_INFO af;
	af.Reset();

	BYTE Frame = AnimIndex;
	GetAnimInformation(af, ID, Offset, Frame);
	
	if (af.Width)
	{
		int OffsCX = 0;
		int OffsCY = 0;
		
		if (Mirror) OffsCX = (af.Width - af.ImageCenterX);
		else OffsCX = af.ImageCenterX;
		OffsCY = (af.Height + af.ImageCenterY + 3);
		
		//X = g_MouseX - (X - OffsCX);
		//Y = g_MouseY - (Y - OffsCX) - (Z * 4);
		X = g_MouseX - (X - OffsCX);
		Y = g_MouseY - (Y - OffsCY - (Z * 4));

		//trace_printf("AnuimCheck:: X = %i Y = %i\n", X, Y);
		
		if (X > 0 && X < af.Width && Y > 0 && Y < af.Height) return TextAnimPixels(af, X, Y);
	}

	return false;
}
//----------------------------------------------------------------------------
void TAnimationManager::CalculateImageSize(TGameObject *obj)
{
	const int LayerCount = 19;

	int UsedLayers[LayerCount] =
	{
		LAYER_SHIRT, //
		19, //"Arms"
		4, //
		3, //
		24, //"Legs"
		13, //"Torso"
		14, //
		7, //"Gloves"
		17, //
		23, //
		10, //"Neck"
		22, //"Robe"
		11, //"Hair"
		16, //"Beard"
		6, //"Helmet"
		12, //
		1, //"Rhand"
		LAYER_CLOAK, //"Cloak"
		2 //"Lhand"
	};

	BYTE Dir = 0;
	POINT3DF Position = {0.0f, 0.0f, 0};

	obj->GetAnimationInfo(Position, Dir);

	bool Mirror = false;

	switch (Dir)
	{
		case 2:
		case 4:
		{
			if (Dir == 2) Mirror = true;
			Dir = 1;
			break;
		}
		case 1:
		case 5:
		{
			if (Dir == 1) Mirror = true;
			Dir = 2;
			break;
		}
		case 0:
		case 6:
		{
			if (Dir == 0) Mirror = true;
			Dir = 3;
			break;
		}
		case 3:
		{
			Dir = 0;
			break;
		}
		case 7:
		{
			Dir = 4;
			break;
		}
		default: break;
	}

	BYTE AnimIndex = obj->GetAnimIndex();
	BYTE AnimGroup = obj->GetAnimationGroup();
	
	int Offset = (((AnimGroup * 5) + Dir) * 12);
	
	BYTE FrameIndex = AnimIndex;
	
	TGameObject *goi = obj->FindLayer(LAYER_MOUNT);
	
	m_Width = 0;
	m_Height = 0;
	
	ANIM_FRAME_INFO af;
	af.Reset();

	if (goi != NULL) //Draw mount
	{
		BYTE AnimGroupM = obj->GetAnimationGroup(goi->GetMountAnimation());
		int OffsetM = (((AnimGroupM * 5) + Dir) * 12);

		GetAnimInformation(af, goi->GetMountAnimation(), OffsetM, FrameIndex);

		//m_Width

		af.Reset();
	}
	
	FrameIndex = AnimIndex;

	//Draw(obj, DrawX, DrawY, Z, Mirror, Offset, AnimIndex); //Draw character

	if (obj->IsHuman())
	{
		IFOR(l, 0, LayerCount)
		{
			goi = obj->FindLayer(UsedLayers[l]);
			if (goi != NULL && goi->GetAnimID())
			{
				BYTE Frame = FrameIndex;
				af.Reset();
				//Draw(goi, DrawX, DrawY, Z, Mirror, Offset, Frame, goi->GetAnimID()); //Draw layred objects
			}
		}
	}


	/*if (af.Width)
	{
		int OffsCX = 0;
		int OffsCY = 0;
		
		if (Mirror) OffsCX = -(af.Width - af.ImageCenterX);
		else OffsCX = -af.ImageCenterX;
		OffsCY = -(af.Height + af.ImageCenterY + 3);

		UO->m_GL.Draw(af.Texture, X + OffsCX, (Y + OffsCY) - (Z * 4), af.Width, af.Height, Mirror);
	}*/
}
//---------------------------------------------------------------------------
ANIMATION_GROUPS TAnimationManager::GetGroupIndex(WORD ID)
{
	if (ID >= 200)
	{
		if (ID >= 400)
		{
			return AG_PEOPLE;
		}
		else
		{
			return AG_LOW;
		}
	}
	else
	{
		return AG_HIGHT;
	}

	return AG_NONE;
}
//---------------------------------------------------------------------------
int TAnimationManager::GetItemAnimationIndex(WORD ID, int &CurrentIndex, bool &AnimateNext, WORD &Delay)
{
	if (!m_AddressAnimData) return 0;

	DWORD addr = (ID * 68) + 4 * ((ID / 8) + 1);
	PANIM_DATA pad = (PANIM_DATA)(m_AddressAnimData + addr);

	Delay = pad->FrameInterval * (UO->m_ConfigManager.GetStandartItemsAnimationDelay() ? 0x50 : 50);

	bool NoReverse = false;
	bool NoHoldFrame = false;
	bool DelayedNoAnim = false;
	
	if (ID >= 0x112C && ID <= 0x1132) NoReverse = true;
	else if (ID >= 0x113A && ID <= 0x113E) NoReverse = true;
	else if (ID >= 0x1145 && ID <= 0x1149) NoReverse = true;
	else if (ID >= 0x1153 && ID <= 0x115E)
	{
		DelayedNoAnim = true;
		NoReverse = true;
	}
	else if (ID >= 0x11A6 && ID <= 0x11AB) NoReverse = true;
	else if (ID >= 0x11C1 && ID <= 0x11C5)
	{
		DelayedNoAnim = true;
		NoReverse = true;
	}
	else if (ID >= 0x12EE && ID <= 0x134B) NoHoldFrame = true;
	else if (ID >= 0x1741 && ID <= 0x181C) NoReverse = true;
	else if (ID >= 0x19D3 && ID <= 0x19E4) NoReverse = true;
	else if (ID >= 0x1ED9 && ID <= 0x1EFC) NoReverse = true;
	else if (ID >= 0x1FA3 && ID <= 0x34B4) NoReverse = true;
	else if (ID >= 0x34D1 && ID <= 0x399F) NoReverse = true;

	if (AnimateNext)
	{
		if (CurrentIndex < pad->FrameCount)
		{
			BYTE result = pad->FrameData[CurrentIndex];
			CurrentIndex++;
			return result;
		}
		else
		{
			if (NoReverse)
			{
				if (DelayedNoAnim) Delay = Delay * pad->FrameCount;
				CurrentIndex = 0;
				return pad->FrameData[0];
			}

			AnimateNext = false;
			BYTE result = pad->FrameData[CurrentIndex];
			CurrentIndex  +=(int)(NoHoldFrame);
			return result;
		}
	}
	else
	{
		if (CurrentIndex < 1)
		{
			AnimateNext = true;
			BYTE result = pad->FrameData[CurrentIndex];
			CurrentIndex  +=(int)(NoHoldFrame);
			return result;
		}
		else
		{
			BYTE result = pad->FrameData[CurrentIndex];
			CurrentIndex--;
			return result;
		}
	}

	return pad->FrameData[CurrentIndex];
}
//----------------------------------------------------------------------------